SQlite源码分析

触发器编码(Code)

代码分析:

void sqlite3CodeRowTrigger(
Parse *pParse,       /* 语法分析器 */
Trigger *pTrigger,   /* pTab上的触发器列表 */
int op,              /* TK_UPDATE, TK_INSERT, TK_DELETE中的一个 */
ExprList *pChanges,  /* 修改列表的任何触发器的UPDATE,如果操作是UPDATE,那么参数pChanges被传递到正在被修改的列表行*/
int tr_tm,           /* TRIGGER_BEFO RE, TRIGGER_AFTER中的一个 */
Table *pTab,         /* 编码触发器来自的表*/
int reg,             /* 寄存器的数组的第一个*/
int orconf,          /* ON CONFLICT 规则*/
int ignoreJump       /* 转到RAISE(IGNORE)的指令 */
){
Trigger *p;
assert(op == TK_UPDATE || op == TK_INSERT || op == TK_DELETE);
assert(tr_tm == TRIGGER_BEFORE || tr_tm == TRIGGER_AFTER);
assert((op == TK_UPDATE) == (pChanges != 0));

各种值不为空。 触发器和表的模式总是被定义的。 触发器必须和表在相同的模式,否则必须是临时触发器。

for (p = pTrigger; p; p = p->pNext){
assert(p->pSchema != 0);
assert(p->pTabSchema != 0);
assert(p->pSchema == p->pTabSchema|| p->pSchema == pParse->db->aDb[1].pSchema);
if (p->op == op&& p->tr_tm == tr_tm&& checkColumnOverlap(p->pColumns, pChanges)
){
sqlite3CodeRowTriggerDirect(pParse, p, pTab, reg, orconf, ignoreJump);
}
}
}

 

void sqlite3CodeRowTriggerDirect(
……
){
Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM 主虚拟存贮器 */
TriggerPrg *pPrg;
pPrg = getRowTrigger(pParse, p, pTab, orconf);

判断

assert(pPrg || pParse->nErr || pParse->db->mallocFailed);
if (pPrg){
    int bRecursive = (p->zName && 0 == (pParse->db->flags&SQLITE_RecTriggers));
    sqlite3VdbeAddOp3(v, OP_Program, reg, ignoreJump, ++pParse->nMem);
    sqlite3VdbeChangeP4(v, -1, (const char *)pPrg->pProgram, P4_SUBPROGRAM);
    VdbeComment((v, "Call: %s.%s", (p->zName ? p->zName : "fkey"), onErrorText(orconf)));

在VDBE对Trigger语句进行编码

    sqlite3VdbeChangeP5(v, (u8)bRecursive);
}
}

 

static TriggerPrg *getRowTrigger(
……){
Parse *pRoot = sqlite3ParseToplevel(pParse);
TriggerPrg *pPrg;
assert(pTrigger->zName == 0 || pTab == tableOfTrigger(pTrigger));

也许这个触发器已经被编码(或在被编码过程中),找到他。

for (pPrg = pRoot->pTriggerPrg;pPrg && (pPrg->pTrigger != pTrigger || pPrg->orconf != orconf);pPrg = pPrg->pNext);

没有则创建新的

if (!pPrg){
pPrg = codeRowTrigger(pParse, pTrigger, pTab, orconf);
}
return pPrg;
}

 

static TriggerPrg *codeRowTrigger(……){
……
TriggerPrg *pPrg;

构建TriggerPrg及其子程序对象

pPrg = sqlite3DbMallocZero(db, sizeof(TriggerPrg));
if (!pPrg) return 0;
pPrg->pNext = pTop->pTriggerPrg;
pTop->pTriggerPrg = pPrg;
pPrg->pProgram = pProgram = sqlite3DbMallocZero(db, sizeof(SubProgram));
if (!pProgram) return 0;

为了确保出错时,他们被释放,必须尽早将他们链接到顶级解析对象Parse.pTriggerPrg列表。

sqlite3VdbeLinkSubProgram(pTop->pVdbe, pProgram);
pPrg->pTrigger = pTrigger;
pPrg->orconf = orconf;
pPrg->aColmask[0] = 0xffffffff;
pPrg->aColmask[1] = 0xffffffff;
……

构建一个语法分析器,用于编码触发器子程序。

Parse *pSubParse;
pSubParse = sqlite3StackAllocZero(db, sizeof(Parse));
if (!pSubParse) return 0;
memset(&sNC, 0, sizeof(sNC));
sNC.pParse = pSubParse;
pSubParse->db = db;
pSubParse->pTriggerTab = pTab;
pSubParse->pToplevel = pTop;
pSubParse->zAuthContext = pTrigger->zName;
pSubParse->eTriggerOp = pTrigger->op;
pSubParse->nQueryLoop = pParse->nQueryLoop;
v = sqlite3GetVdbe(pSubParse);
if (v){
VdbeComment((v, “Start: %s.%s (%s %s%s%s ON %s)”, /* 输出错误信息*/
pTrigger->zName, onErrorText(orconf),
(pTrigger->tr_tm == TRIGGER_BEFORE ? "BEFORE" : "AFTER"),
(pTrigger->op == TK_UPDATE ? "UPDATE" : ""),
(pTrigger->op == TK_INSERT ? "INSERT" : ""),
(pTrigger->op == TK_DELETE ? "DELETE" : ""),
pTab->zName
));
……

如果代码WHEN子句被指定,它的求值结果为false(或NULL),则sub-vdbe立即停止

if (pTrigger->pWhen){
pWhen = sqlite3ExprDup(db, pTrigger->pWhen, 0);
if (SQLITE_OK == sqlite3ResolveExprNames(&sNC, pWhen)
&& db->mallocFailed == 0
){
iEndTrigger = sqlite3VdbeMakeLabel(v);
sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger,    SQLITE_JUMPIFNULL);
}
sqlite3ExprDelete(db, pWhen);
}

触发器程序编码进入sub-vdbe

codeTriggerProgram(pSubParse, pTrigger->step_list, orconf);
if (iEndTrigger){
sqlite3VdbeResolveLabel(v, iEndTrigger);
}
sqlite3VdbeAddOp0(v, OP_Halt);

子程序最后加入停止命令

VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf)));
transferParseError(pParse, pSubParse);
if (db->mallocFailed == 0){
pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg);
}
……}……

返回构建的Trigger

return pPrg;
}

 

static int codeTriggerProgram(……){
TriggerStep *pStep;
Vdbe *v = pParse->pVdbe;
sqlite3 *db = pParse->db;
assert(pParse->pTriggerTab && pParse->pToplevel);
assert(pStepList);
assert(v != 0);

对每一步进行循环

for (pStep = pStepList; pStep; pStep = pStep->pNext){

计算出需要在触发器子进程中使用的ON CONFLICT规则

    pParse->eOrconf = (orconf == OE_Default) ? pStep->orconf : (u8)orconf;
    ……
}

static int codeTriggerProgram(……){
……
switch (pStep->op){
case TK_UPDATE: {
    sqlite3Update(pParse,targetSrcList(pParse, pStep),sqlite3ExprListDup(db, pStep->pExprList, 0),
    sqlite3ExprDup(db, pStep->pWhere, 0),pParse->eOrconf);
break;}
case TK_INSERT: {
    sqlite3Insert(pParse,targetSrcList(pParse, pStep),sqlite3ExprListDup(db, pStep->pExprList, 0),sqlite3SelectDup(db, pStep->pSelect, 0),
    sqlite3IdListDup(db, pStep->pIdList),pParse->eOrconf);
break;}
case TK_DELETE: {
sqlite3DeleteFrom(pParse,targetSrcList(pParse, pStep),sqlite3ExprDup(db, pStep->pWhere, 0));
break;}

根据pStep->op的值进行判断,分别进行UPDATE、INSERT、DELETE和SELECT操作

default: assert(pStep->op == TK_SELECT); {
 SelectDest sDest;
 Select *pSelect = sqlite3SelectDup(db, pStep->pSelect, 0);
 sqlite3SelectDestInit(&sDest, SRT_Discard, 0);
 sqlite3Select(pParse, pSelect, &sDest);
 sqlite3SelectDelete(db, pSelect);
 break;}}
if (pStep->op != TK_SELECT){
sqlite3VdbeAddOp0(v, OP_ResetCount);
}
}
return 0;
}